/**
 *  Copyright 2002-2009 the original author or authors.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package foo.bar.blog.web.action;

import foo.bar.blog.web.extension.PaginatedListSortConverter;
import net.sourceforge.stripes.validation.Validate;
import org.apache.commons.lang.StringUtils;
import org.displaytag.properties.SortOrderEnum;

/**
 * An extension of {@link foo.bar.blog.web.action.BaseActionBean} that adds pagination capabilities.
 * <p/>
 * Upon extending from this action bean, the request accepts the following request parameters :-
 * <ul>
 *  <li>sort - the DisplayTag column name for sorting</li>
 *  <li>dir - either 'ascending' or 'descending'</li>
 *  <li>page - the page number, starts with 1</li>
 *  <li>objectsPerPage - number of entries per page, starts with 1</li>
 * </ul>
 *
 *
 * @author tmjee
 * @version $Date: 2009-03-14 06:53:07 +0000 (Sat, 14 Mar 2009) $ $Id$
 */
public class PaginatedBaseActionBean extends BaseActionBean {

    public static final int DEFAULT_OBJECTS_PER_PAGE = 10;



    private String sort;

    @Validate(converter = PaginatedListSortConverter.class)
    private SortOrderEnum dir;

    private int page;
    private int objectsPerPage;

    /**
     * Set the sort request parameter.
     * @return
     */
    public String getSort() {
        return sort;
    }

    /**
     * Get the sort request parameter.
     * @param sort
     */
    public void setSort(String sort) {
        this.sort = sort;
    }

    public SortOrderEnum getDir() {
        return dir;
    }

    /**
     * Set the dir request parameter.
     * @param dir
     */
    public void setDir(SortOrderEnum dir) {
        this.dir = dir;
    }

    /**
     * Get the dir request parameter
     * @return int
     */
    public int getPage() {
        return page;
    }

    /**
     * Set the page request parameter.
     * @param page
     */
    public void setPage(int page) {
        this.page = page;
    }

    /**
     * Get the objectsPerPage request parameter
     * @return int
     */
    public int getObjectsPerPage() {
        return objectsPerPage;
    }

    /**
     * Set the objectsPerPage request parameter
     * @param objectsPerPage
     */
    public void setObjectsPerPage(int objectsPerPage) {
        this.objectsPerPage = objectsPerPage;
    }



    /**
     * Get a {@link foo.bar.blog.web.action.ExtendedPaginatedList}, the name of this paginated list used to
     * identified it in the http session will be generated based on <code>paginatedListName<code> given,
     * subsequent call to this method with the same <code>paginatedListName</code> will get back the same
     * {@link foo.bar.blog.web.action.ExtendedPaginatedList}.
     * 
     * @param paginatedListName
     * @return
     */
    protected ExtendedPaginatedList getPaginatedList(String paginatedListName) {
        if (paginatedListName == null) {
            return getPaginatedList();
        }
        return getPaginatedListFromSession(paginatedListName);
    }


    /**
     * Get a default {@link foo.bar.blog.web.action.ExtendedPaginatedList}, the name of this paginated list used to
     * identified it in the http session will be auto-generated.
     * 
     * @return {@link foo.bar.blog.web.action.ExtendedPaginatedList}
     */
    protected ExtendedPaginatedList getPaginatedList() {
        return getPaginatedListFromSession(null);
    }

    /**
     * Remove {@link ExtendedPaginatedList} from http session based on <code>paginatedListName</code>
     * 
     * @param paginatedListName
     */
    protected void clearPaginatedList(String paginatedListName) {
        String sessionAttributeName = generatePaginatedListName(paginatedListName);
        setSessionAttribute(sessionAttributeName, null);
    }

    /**
     * Attempt to :-
     * 1] Get an {@link foo.bar.blog.web.action.ExtendedPaginatedList} from session with a key generated based on
     * <code>paginatedListName</code> and populate them with the pagination info (sort, dir, page etc.) if
     * pagination info are not supplied, those from previously stored values will be used.
     * 2] if not possible, create one and populate with the pagination info (sort, dir, page, etc.) if they
     * are not available from current request, default value will be used, objects will be null and int will be zeros
     *
     * @param paginatedListName
     * @return {@link foo.bar.blog.web.action.ExtendedPaginatedList}
     */
    private ExtendedPaginatedList getPaginatedListFromSession(String paginatedListName) {
        String sessionAttributeName = generatePaginatedListName(paginatedListName);

        ExtendedPaginatedList _sessionPaginatedList = (ExtendedPaginatedList)
                getSessionAttribute(sessionAttributeName);
        ExtendedPaginatedList paginatedList = new ExtendedPaginatedListImpl();

        if (_sessionPaginatedList != null) {
                paginatedList.setSortCriterion(StringUtils.isEmpty(sort)?_sessionPaginatedList.getSortCriterion():sort);
                paginatedList.setSortDirection(dir==null?_sessionPaginatedList.getSortDirection():dir);
                paginatedList.setPageNumber(page <= 0 ? _sessionPaginatedList.getPageNumber() : page);
                paginatedList.setObjectsPerPage(objectsPerPage <= 0 ? DEFAULT_OBJECTS_PER_PAGE : objectsPerPage);
        }
        else {
            paginatedList.setSortCriterion(sort);
            paginatedList.setSortDirection(dir);
            paginatedList.setPageNumber(1);
            paginatedList.setObjectsPerPage(objectsPerPage <= 0 ? DEFAULT_OBJECTS_PER_PAGE : objectsPerPage);
        }
        setSessionAttribute(sessionAttributeName, paginatedList);
        return new ExtendedPaginatedListImpl(paginatedList);
    }

    /**
     * Generates a unique pagination list name based on <code>paginatedListName</code>
     * <p/>
     * It's either
     * <code>
     *     {@link #getActionId()}ExtendedPaginatedList
     * </code>
     * when <code>paginatedListName</code> is null or
     * <code>
     *     {@link #getActionId()}paginatedListName_ExtendedPaginatedList
     * </code>
     *
     * @param paginatedListName
     * @return String
     */
    private String generatePaginatedListName(String paginatedListName) {
        return paginatedListName == null ? getActionId()+"ExtendedPaginatedList" : getActionId()+paginatedListName+"_ExtendedPaginatedList";
    }
}
